var cheerio = require('cheerio');
var Req = require('./req');
var needle = require('needle');
var fs = require('fs');
var macAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36' +
' (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36';

function Spider(_atob, callback) {
    this._atob = _atob;
    this.tasks = [];
    this.running = -1;  // -1 未开始, 0 停止, 1 运行, 2 暂停
    this.complete = [];
    this.failure = [];
    this.sogouHeaders = {};
    this.sogouCookiesStr1 = 'weixinIndexVisited=1';
    this.sogouCookiesStr2 = '';
    this.callback = callback;
    this.noSleep = false;

    // promise延时处理，默认10~20秒时间间隔
    this._retTimeout = function(res, time, force) {
        var _time = time || 10000;
        if (this.noSleep) {
            // 关闭等待时
            return Promise.resolve(res);
        }
        return new Promise(function(resolve) {
            setTimeout(function() {
                resolve(res || null);
            }, _time + parseInt(_time * Math.random(), 10));
        });
    }

    this._randomTime = function(t) {
        return parseInt(t* Math.random(), 10)
    }
    this.start = function(tasks) {
        // 检查状态再进行操作，控制值守时间等
        var self = this;
        this.running = 1;
        this.tasks = tasks;

        console.log('start:::::', this.tasks.length);
        this.allTasksNum = this.tasks.length;

        // 获取cookie之后5s开始执行任务
        this._updateSogouCookie().then(function(){
            return self._retTimeout(null);
        }).then(function(){
            self._doTask();
        });
    }

    // 递归执行任务
    this._doTask = function() {
        var self = this;
        console.log('current status:', this.tasks.length);
        if (!this.tasks.length) {
            this.callback.onDone && this.callback.onDone();
            this._stop();
            return;
        }
        // 如果是暂停,延时后继续下一次轮训
        if (this.running === 2 || this.running === 0) {
            console.log('已停止或者暂停');
            // console.log('暂停，等待下一次尝试.', Date.now(), this.tasks.length);
            // self._retTimeout(null, 5000, true).then(function(){
            //     self.reStart();
            //     self._doTask();
            // });
            return;
        }

        var task = this.tasks.shift();
        this.currentTask = task;
        this.callback.onTaskStart && this.callback.onTaskStart(task);
        console.log('do task::', task);
        this._search(task).then(function(taskRes){
            console.log('one task done.');
            self.complete.push(task);
            // 发送给服务器
            self.callback.onTaskComplete && self.callback.onTaskComplete(task, taskRes);
            self.sendTaskResult([task, taskRes]);
            // 一个账号成功, 更新cookie，延时后继续
            self._retTimeout().then(function(){
                return self._updateSogouCookie();
            }).then(function(){
                self._doTask();
            });
        }).catch(function(e){
            self.failure.push(task);
            self.callback.onTaskFailure && self.callback.onTaskFailure(task);
            //记录一条失败, 延时后继续
            console.log('one task error:', e);
            self._retTimeout().then(function(){
                return self._updateSogouCookie();
            }).then(function(){
                self._doTask();
            }).catch(function(){
                self._doTask();
            });
        });
    }

    // 搜索账号
    this._search = function(task) {
        var self = this;
        return new Promise(function(resolve, reject){
            // 按页递归查找，判断账号是否匹配
            function _doSearch(page) {
                console.log('search:page:', page);
                // 最大搜索页
                if (page >= 2) {
                    reject('没有找到账号');
                    return;
                }

                // 暂停时直接结束
                if (self.running === 2 || self.running === 0) {
                    reject('pause-stop');
                    return;
                }
                self._searchPage(task.wx_alias || task.name, 0).then(function(res){
                    // console.log('page res:', res);
                    // 解析当前搜索结果页中的账号列表
                    var info = self._parsePageAccounts(res);
                    if (!info.length) {
                        // 没有info则是302，被搜狗屏蔽了，更新cookie
                        return self._retTimeout().then(function(){
                            return self._updateSogouCookie();
                        }).then(function(){
                            return 302;
                        });
                    }
                    // console.log('info::', info);
                    // 有wx_alias时，更具info列表来筛选出账号
                    if (task.wx_alias) {
                        var hasAccount = false;
                        info.forEach(function(item) {
                            if (item.account === task.wx_alias){
                                hasAccount = item;
                            }
                        });
                        if (hasAccount) {
                            console.log('find account by alias:');
                            // 当页列表中找到了账号，直接抓取该账号完整数据
                            return self.crawlAccountDetail(hasAccount);
                        }
                        return false;
                    }
                    // 递归info列表，获取搜索账号更多信息来判断是否有匹配的账号
                    return self._searchInfoList(info, task);
                }).then(function(accountRes){
                    console.log('one page done.');
                    if(accountRes === 302) {
                        console.log('302');
                        // self.tasks = [task].concat(self.tasks);
                        // self.pause();
                        reject(false);
                        return;
                    }
                    //一页处理完了之后，还是没有账号，延时后下一页
                    if (!accountRes) {
                        _doSearch(page+1);
                        // self._retTimeout().then(function(){
                        //
                        // });
                        return;
                    }
                    console.log('find account:has data');
                    resolve(accountRes);
                }).catch(function(e) {
                    reject(e);
                });
            }
            _doSearch(0);
        });
    }

    this._searchPage = function(kw, page) {
        var self = this;
        var _kw = encodeURIComponent(kw);
        var getListUrl =
        // `http://weixin.sogou.com/weixin?type=1&query=${_kw}&ie=utf8&_sug_=n&_sug_type_=`;
        `http://weixin.sogou.com/weixin?type=1&query=${_kw}&ie=utf8&_sug_=y&_sug_type_=&w=&sut=2138&sst0=1481270747189&lkt=3%2C1481270745515%2C1481270745702`;
        if (page && page !== 1) {
            getListUrl += `&page=${page}`;
        }
        self.sogouHeaders = self._getSogouHeaders();
        return Req.get(getListUrl, {
            multiReturn: true,
            headers: self.sogouHeaders
        }).then(function(res) {
            console.log(res.res.statusCode, res.res.headers.location);
            console.log('search:kw:', kw);
            if (res.res.statusCode ===302) {
                self.callback.onSouGouVerify && self.callback.onSouGouVerify(res.res.headers.location);
                // self.getSGCode();
                // self.pause();
                throw new Error(302);
            }
            // 从搜索结果页面里更新cookie的suv值
            console.log(res);
            var suvMatch = res.body.match(/wuid".*?"(.*?)"/);
            self._stop();
            // if (suvMatch) {
                // console.log(res.body);
                // console.log('update SUV:', suvMatch[1]);
                // self.sogouCookiesStr1 = self.sogouCookiesStr1.replace(/;SUV=.*$/, '');
                // self.sogouCookiesStr1 += ';SUV=' + suvMatch[1];
            // }
            return res.body;
        });
    }

    this._parsePageAccounts = function(html) {
        var $ = cheerio.load(html, { decodeEntities: false });
        var info = [];
        $('.news-list2>li').map(function (i, item) {
            var infoDom = $(item).find('.txt-box .info');
            var _info = {};
            // 微信号
            _info.account = $(infoDom).find('label').html();
            // 微信链接
            _info.url = $(item).find('.tit a').attr('href');
            // 月发文
            var _articleNum = parseInt($(infoDom).html().split('月发文')[1], 10);
            if (_articleNum) {
                _info.articleNum = _articleNum;
            }
            // 平均阅读
            var _readNum = parseInt($(infoDom).html().split('平均阅读')[1], 10);
            if (_readNum) {
                _info.readNum = _readNum;
            }
            var links = $(item).find('a');
            _info.lastLink = $(links[links.length - 1]).attr('href');
            info.push(_info);
            return null;
        });
        console.log('find info::');
        return info;
    }

    this._searchInfoList = function(info, task) {
        var self = this;
        return new Promise(function(resolve, reject) {
            function _doSearch() {
                if (!info.length) {
                    console.log('没有找到匹配的账号');
                    reject(false);
                    return;
                }

                // 暂停时直接结束
                if (self.running === 2 || self.running === 0) {
                    reject(false);
                    return;
                }

                var infoItem = info.shift();

                // 没有最后一盘文章的，直接跳过
                if (!infoItem.lastLink) {
                    reject(false);
                    return;
                }
                //先抓取一片文章，来判断账户的uin是否匹配
                self._getLastArticle(infoItem.lastLink).then(function(linkRes){
                    console.log('lastlink::', linkRes.bizuin, linkRes.nick_name);
                    // 如果没有文章或者没有bizuin， 延时后继续找下一个账号
                    if (!linkRes || !linkRes.bizuin) {
                        self._retTimeout().then(function(){
                            _doSearch();
                        });
                        return;
                    }
                    // biz不匹配，延时后继续下一个
                    if (self._atob(linkRes.bizuin) !== task.uin){
                        self._retTimeout().then(function(){
                            _doSearch();
                        });
                        return;
                    }
                    // 匹配到了账号, 获取完整的8篇文章
                    console.log('find account:');
                    self.crawlAccountDetail(infoItem, 8).then(function(accountMoreRes){
                        resolve(accountMoreRes);
                    }).catch(function(e){
                        console.log(e);
                        reject(false);
                    });
                }).catch(function(e){
                    console.log(e);
                    reject(false);
                });
            }
            _doSearch();
        });
    }

    this._stop = function() {
        this.running = 0;
        this.tasks = [];
        this.allTasksNum = 0;
        this.complete = [];
        this.failure = [];
        console.log('all done.');
    }

    this._getSogouHeaders = function() {
        // TODO：每次只要更新cookie就能保证info获取正常，尝试用webview更新
        console.log('cooie::::', this.sogouCookiesStr1 + this.sogouCookiesStr2);
        // TODO：每次只要更新cookie就能保证info获取正常，尝试用webview更新
        return {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Encoding': 'gzip, deflate, sdch',
            'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive',
            'Cookie': '' + this.sogouCookiesStr1 + this.sogouCookiesStr2,
            'Host': 'weixin.sogou.com',
            'Pragma': 'no-cache',
            'Upgrade-Insecure-Requests': 1,
            'User-Agent': macAgent
        };
    }

    // 获取一个账号的更多详细
    this.crawlAccountDetail = function(item, articleCount) {
        var self = this;
        var url = item && item.url.replace(/&amp;/g, '&');
        console.log('account page::', url);
        return self._getAccountPage(url || '').then(function (res) {
            var accountData = self._getAccountPageContent(res, item);
            // 数据不完整，没有抓到
            if (!accountData.msgList) {
                // self.tasks = [self.currentTask].concat(self.tasks);
                // self.pause();
                throw new Error('账号页面被微信屏蔽');
            }
            // 延迟5秒去抓取文章数据
            return self._retTimeout(null, 5000).then(function(){
                return self.crawlEveryArticle(accountData, articleCount);
            }).then(function(articleRes){
                accountData.articles = articleRes;
                return accountData;
            });
        });
        // .catch(function (e) {
        //     // 获取文章超时
        //     console.warn(164);
        //     console.warn(e);
        //     return {
        //         info: item, // avatar name desc company
        //         msgList: [],
        //         articles: []
        //     };
        // });
    }

    // 获取微信账户首页
    this._getAccountPage = function(url) {
        // console.log('Req:', url);
        return Req.get(url, {
            // cookies: cookiesMap,
            headers: {
                'User-Agent': macAgent,
                'Cookie': ''
            }
        });
    }

    this._getLastArticle = function(url) {
        console.log('last article url::', url);
        return this._getArticleJson(url.replace(/amp;/g, '') + '&f=json');
    }

    // 获取账户页面详情
    this._getAccountPageContent = function(res, item) {
        var $ = cheerio.load(res, { decodeEntities: false });
        var msgListMatch = res.match(/var msgList =(.*)/);
        var msgList = msgListMatch ? JSON.parse(msgListMatch[1].trim().match(/({.+});/)[1]) : [];
        var content = {
            info: item, // avatar name desc company
            articles: []
        };
        try {
            content.info.avatar = $('.radius_avatar img').attr('src');
            content.info.name = $('.profile_nickname').html().trim();
            content.info.desc = $('.profile_desc_value').eq(0).html();
            content.info.wx_verify = $('.icon_verify').length ? 1 : 0;
            var _html = $('.profile_desc_value').eq(1).html();
            var _company = _html.split('">')[1];
            if (_company) {
                content.info.company = _company;
            }
            content.msgList = msgList;
        } catch (e) {
            console.log('出现微信验证码了');
            console.log($('.weui_cell_hd').html());
        }
        return content;
    }

    this._updateSogouCookie = function() {
        var _this = this;
        var cookieStr = '';
        return new Promise(function (resolve, reject) {
            needle.get('http://weixin.sogou.com/', function (error, response) {
                if (error) {
                    console.log(error);
                    reject(error)
                    return;
                }
                var cookiesMap = response.cookies;
                if (cookiesMap) {
                    Object.keys(cookiesMap).forEach(function (key) {
                        cookieStr += '; ' + key + '=' + cookiesMap[key];
                    });
                }
                _this.sogouCookiesStr2 = cookieStr;
                resolve(cookieStr.substr(2));
            });
        });
    }

    this._changeArticleUrl = function(url) {
        var temp = url.replace(/&amp;/g, '&').replace(/#wechat_redirect/g, '');
        if (temp) {
            if (!/http:\/\/mp\.weixin\.qq\.com/.test(temp)) {
                return 'http://mp.weixin.qq.com' + temp + '&f=json';
            }
            return temp + '&f=json';
        }
        return '';
    }

    // 获取一个账号下的8篇文章
    this.crawlEveryArticle = function (account, maxArticle) {
        var self = this;
        var resultAll = [];
        var sourceUrl = [];
        if (account.msgList && account.msgList.list.length) {
            // account.msgList.list = account.msgList.list.splice(0, 8);
            account.msgList.list.forEach(function (msg) {
                // console.log('i:::::', i);
                sourceUrl.push(self._changeArticleUrl(msg.app_msg_ext_info.content_url));
                msg.app_msg_ext_info.multi_app_msg_item_list.forEach(function (msgItem) {
                    sourceUrl.push(self._changeArticleUrl(msgItem.content_url));
                });
            });
        }
        // 只获取8篇文章
        sourceUrl = sourceUrl.splice(0, maxArticle || 8);
        return new Promise(function(resolve, reject) {
            function __getArticle() {
                // 暂停时直接结束
                if (self.running === 2) {
                    reject(resultAll);
                    return;
                }
                var url = sourceUrl.shift();
                if (!url) {
                    resolve(resultAll);
                    return;
                }
                console.log('获取文章内容:', url, sourceUrl.length, account.info.account);
                self._getArticleJson(url).then(function (res) {
                    if (res.link) {
                        res.content_noencode = '';
                    } else if (url) {
                        res.link = url.split('&f=json')[0];
                    }
                    resultAll.push(res || {});
                    // console.log(res);
                    // 延时抓取下一篇文章
                    self._retTimeout().then(function(){
                        __getArticle();
                    });
                }).catch(function (e) {
                    console.log(e);
                    // 如果出错，把已经抓取成功的文章返回;
                    resolve(resultAll);
                });
            }
            __getArticle();
        });

    }

    this._getArticleJson = function (url) {
        if (!url) {
            Promise.resolve({});
        }
        // 有些情况下_getArticleJson会一直卡住，没有响应，暂时不知道为啥
        console.log('getArticleJson:', url);
        return new Promise(function(resolve, reject){
            var t = setTimeout(function(){
                reject(false);
            }, 30*1000);
            return Req.get(url, {
                headers: {
                    'User-Agent': macAgent,
                    'Cookie': ''
                }
            }).then(function (resJson) {
                var htmlUrl = url.split('&f=json')[0];
                // console.log('Req::', htmlUrl);
                return Req.get(htmlUrl, {
                    headers: {
                        'User-Agent': macAgent,
                        'Cookie': ''
                    }
                }).then(function(resHtml){
                    return {
                        resJson: resJson,
                        resHtml: resHtml
                    }
                });
            }).then(function (res) {
                // TODO：未匹配的情况访问url提示账号被封，等待间隔，cookies判断
                // 解析出授权信息
                var sgData = {};
                if (res.resHtml.match(/window\.sg_data/)) {
                    sgData.src = res.resHtml.match(/src:"(.*?)"/)[1];
                    sgData.ver = res.resHtml.match(/ver:"(.*?)"/)[1];
                    sgData.timestamp = res.resHtml.match(/timestamp:"(.*?)"/)[1];
                    sgData.signature = res.resHtml.match(/signature:"(.*?)"/)[1];
                } else {
                    // 如果没有抓到阅读量和点赞
                    return res.resJson;
                }

                var commentUrl = 'http://mp.weixin.qq.com/mp/getcomment?src=' + sgData.src + '&ver=' + sgData.ver + '&timestamp=' + sgData.timestamp + '&signature=' + sgData.signature + '&&uin=&key=&pass_ticket=&wxtoken=&devicetype=&clientversion=0&x5=0';
                // console.log('req::', commentUrl);
                return Req.get(commentUrl, {
                    headers: {
                        'User-Agent': macAgent,
                        'Cookie': ''
                    }
                }).then(function (resComment) {
                    res.resJson.like_num = resComment.like_num;
                    res.resJson.read_num = resComment.read_num;
                    return res.resJson;
                });
            }).then(function(res) {
                clearTimeout(t);
                return resolve(res);
            }).catch(function(e){
                clearTimeout(t);
                console.log(e);
                reject(e);
            });
        });

    }

    this.getStatus = function() {
        return {
            allTasksNum: this.allTasksNum,
            currentTask: this.currentTask,
            complete: this.complete,
            failure: this.failure,
            tasks: this.tasks
        }
    }

    this.sendTaskResult = function(result) {
        // 保存任务
        console.warn('::::::::::::::saveTaskResult');
        var articles = result[1].articles;
        var info = result[1].info;
        var rawId = '';
        if (articles[0]) {
            info.originId = articles[0].user_name;
            rawId = articles[0].user_name;
        }
        var d = {
            raw_id: rawId,
            articles: articles,
            info: info
        };
        return Req.post('http://api.wxb.com/client/saveback2', {
            t: 'following',
            d: d
        }).then(function (res) {
            console.warn('saved success');
            // console.warn(res);
            // console.warn(d);
        }).catch(function (e) {
            console.warn(e);
        });
    }

    // 暂停，只会暂停后续任务，当前已开始的任务不会暂停
    this.pause = function() {
        this.running = 2;
    }
    // 暂停后，重新启动
    this.reStart = function() {
        // 把上一个失败的重新加入任务
        if (this.failure.length) {
            this.tasks = [this.failure.pop()].concat(this.tasks);
        }
        this.running = 1;
        this._doTask();
    }

    this.sendWXVerifycode = function(code, cert) {
        return Req.post('http://mp.weixin.qq.com/mp/verifycode', {
            input: code,
            cert: cert
        }, {
            headers: {
                Cookie: 'RK=xpsud5YmEC; pgv_pvi=9010373632; tvfe_boss_uuid=b83b298ea5952a83; pac_uid=1_1796925723; mobileUV=1_15861b2806f_44dc6; ts_uid=9301379620; ptui_loginuin=1796925723@qq.com; ptcz=d874df875f96d992b87906e058c650f4570c8399318e918d706620b17b210581; pt2gguin=o1796925723; pgv_pvid=102423856; o_cookie=1796925723; pgv_si=s4444525568; noticeLoginFlag=0; sig=h01035ca1d02dfeccfa13705bc6b7d93c4b112e83720c9831e9c87808970fc1ff6fa7e3c6df8b1699b',
                Referer: 'http://mp.weixin.qq.com/profile?src=3&timestamp=1481777091&ver=1&signature=9x--igofVwzy6ITnIlna32-o-79I1DsMb9fOj-1W9VEyhhQAm8C1EF4b-Tp7JcLdZenWzIZkhpAIbZrTzEACpw==',
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
                'X-Requested-With': 'XMLHttpRequest'
            }
        }).then(function (res) {
            console.warn(res);
            return res;
        });
    }
    this.getSGCode = function(){
        var time = Date.now();
        return Req.get('http://weixin.sogou.com/antispider/util/seccode.php?tc=' + time, {
            headers: {
                Cookie: this.sogouCookiesStr1 + this.sogouCookiesStr2
            }
        }).then(function (res) {
            console.log('write code::', time);
            fs.writeFileSync('./1.jpg', res, {
                encoding: 'binary'
            });
            return time;
        });
    }
    this.sendSGVerifycode = function(code) {
        return Req.post('http://weixin.sogou.com/antispider/thank.php', {
            c: code,
            r: '',
            v: 5
        }, {
            headers: {
                'X-Requested-With': 'XMLHttpRequest',
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
                Referer: 'http://weixin.sogou.com/antispider/',
                Cookie: 'ABTEST=5|1481679642|v1; SUID=4BFBEF7C2219920A000000005850A31A; SUID=6D966DDA1808990A000000005850A31A; weixinIndexVisited=1; SUV=00D77351DA6D966D5850A31B7BF26174; SNUID=83B29B98EAEFA97E9481E355EA492F50; JSESSIONID=aaavcRHRoPkax4i1qNCJv; pgv_pvi=1729041408; pgv_si=s4184983552; sct=22; PHPSESSID=fud99ck1prucvhohsvr8ovnjd1; SUIR=83B29B98EAEFA97E9481E355EA492F50; IPLOC=CN1300; seccodeErrorCount=1|Thu, 15 Dec 2016 09:16:05 GMT'
            }
        }).then(function (res) {
            fs.writeFileSync('./1.html', res, {
                encoding: 'binary'
            });
            console.log(res);
            return res;
        });
    }
}

module.exports = Spider;
